#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#---------------------------------------------
#  gcl_sdk python
#
#  2018/03/27
#---------------------------------------------

import time,re,os,ReadConfig
from log import Logger
from queue import Queue
from ctypes import *
from struct import *
import ygct_common
from gcl_sdk import *

#遥信结构体
class GCL_YX_T(Structure):
    _fields_=[
        ('address',c_int),
        ('value', c_int),
        ('quality', c_int),
        ('datetime', c_longlong)
        ]
#遥测结构体
class GCL_YC_T(Structure):
    _fields_=[
        ('address',c_int),
        ('value', c_double),
        ('quality', c_int),
        ('datetime', c_longlong)
        ]
#遥文结构体
class GCL_YW_T(Structure):
    _fields_=[
        ('address',c_int),
        ('value', c_char*128),
        ('quality', c_int),
        ('datetime', c_longlong)
        ]
#结构体
class GCL_PSM_ATTACH(Structure):
    _fields_=[
        ('reason',c_int),
        ('containerId', c_int),
        ('sourceId', c_int),
        ('targetId', c_int),
        ('tag', c_int)
        ]

CALLBACK_SDK_ERR      = ygct_common.method(CFUNCTYPE(None, c_int))
CALLBACK_SDK_MSG      = ygct_common.method(CFUNCTYPE(None, c_char_p, c_char_p,c_int, POINTER(GCL_PSM_ATTACH)))
CALLBACK_SDK_FILE     = ygct_common.method(CFUNCTYPE(None, c_char_p,POINTER(GCL_PSM_ATTACH)))
CALLBACK_SDK_RT_REQ   = ygct_common.method(CFUNCTYPE(None, POINTER(GCL_PSM_ATTACH)))
CALLBACK_SDK_RT_REV   = ygct_common.method(CFUNCTYPE(None, c_int,c_void_p,c_int,c_int,POINTER(GCL_PSM_ATTACH)))

#SDK
class GCL_SDK:
    def __init__(self,log):
        self.lib = CDLL(os.path.abspath("./gcl_sdk.dll"))
        self.log=log

    def reg_err_notify(self,fn):
        return self.lib.gci_register_error_notify(fn)

    def unreg_err_notify(self,fn):
        return self.lib.gci_unregister_error_notify(fn)

    def reg_msg_cmd_notify(self,fn):
        return self.lib.gci_register_message_command_notify(fn)

    def unreg_msg_cmd_notify(self,fn):
        return self.lib.gci_unregister_message_command_notify(fn)

    def reg_file_transfer_notify(self,fn):
        return self.lib.gci_register_file_transfer_notify(fn)

    def unreg_file_transfer_notify(self,fn):
        return self.lib.gci_unregister_file_transfer_notify(fn)

    def reg_file_transfer_result_notify(self,fn):
        return self.lib.gci_register_file_transfer_result_notify(fn)

    def unreg_file_transfer_result_notify(self,fn):
        return self.lib.gci_unregister_file_transfer_result_notify(fn)

    def reg_rt_rev_notify(self,fn):
        return self.lib.gci_register_realtime_data_post_notify(fn)

    def unreg_rt_rev_notify(self,fn):
        return self.lib.gci_unregister_realtime_data_post_notify(fn)

    def init(self,argc,argv):
        return self.lib.gci_init(argc,argv)

    def uninit(self):
        return self.lib.gci_cleanup()

    def send_msg(self,cmd,pram,lenth,attach):


        return self.lib.gci_message_command_send(cmd,pram,lenth,attach)

    def send_yx(self,e):
        buff =  pack('=iiiq',e.address, e.value, e.quality, e.datetime)
        return self.lib.gci_realtime_data_post(0x01010203, buff, 20,1, None)

    def send_yc(self,e):
        buff =  pack('=idiq',e.address, e.value, e.quality, e.datetime)
        return self.lib.gci_realtime_data_post(0x0101021C, buff, 24,1, None)

    def send_yw(self,e):
        buff =  pack('=i128siq',e.address, e.value, e.quality, e.datetime)
        return self.lib.gci_realtime_data_post(0x0101022F, buff, 144,1, None)

    def send_yx_array(self,v):
        if len(v) >0:
            buff = b''
            for e in v:
                buff += (pack('=iiiq',e.address, e.value, e.quality, e.datetime))
            return self.lib.gci_realtime_data_set_list(0x01010203, buff, 20*len(v),len(v), None)
        return -1

    def send_yc_array(self,v):
        if len(v) >0:
            buff = b''
            for e in v:
                buff += (pack('=idiq',e.address, e.value, e.quality, e.datetime))
            return self.lib.gci_realtime_data_set_list(0x0101021C, buff, 24*len(v),len(v), None)
        return -1

    def send_yw_array(self,v):
        if len(v) >0:
            buff = b''
            for e in v:
                buff += (pack('=i128siq',e.address, e.value, e.quality, e.datetime))
            return self.lib.gci_realtime_data_set_list(0x0101022F, buff, 144*len(v),len(v), None)

        return -1
#回调
class SDK_CB:
    def __init__(self, obj,log):
        self.parent = obj
        self.log=log
        self.RT={}
        self.MSG=Queue()
    def set_callbacks(self):
        #注册消息回调
        self.parent.sdk.reg_msg_cmd_notify(self.cb_sdk_msg)
        #注册实时回调
        self.parent.sdk.reg_rt_rev_notify(self.cb_sdk_rt_rev)
        #注册文件回调
        self.parent.sdk.reg_file_transfer_result_notify(self.cb_sdk_Filr)

    @CALLBACK_SDK_ERR
    def cb_sdk_error(self, err):
        self.log.error('错误:%s'%err)
    @CALLBACK_SDK_MSG
    #消息回调
    def cb_sdk_msg(self, cmd, pram, length, attach):
        pram=pram.decode('utf-8')
        cmd=cmd.decode('utf-8')
        self.log.info('命令：%s,接收到消息：%s'%(cmd,pram))
        self.MSG.put((cmd,pram))
     #文件回调
    @CALLBACK_SDK_FILE
    def cb_sdk_Filr(self, file, attach):

        print('文件:',file, attach)
    @CALLBACK_SDK_RT_REQ
    def cb_sdk_rt_req(self, attach):
        #print(attach)
        pass
    #实时回调
    @CALLBACK_SDK_RT_REV
    def cb_sdk_rt_rev(self, rt_rtype, data, size, count, attach):
        x = cast(data, POINTER(c_char*size))
        #报文
        x = bytes([v[0] for v in x.contents])
        #长度
        step = int(size/count)
        if rt_rtype == 0x01010203 and count>0:
            for i in range(0, size, step):
                value=unpack('=iiiq', x[i: i+step])
                #self.log.info('接收遥信%s'%str(value))
                value=list(value)
                value[3]=value[3]/1000
                self.RT.update({value[0]:value})

        elif rt_rtype == 0x0101021C and count>0:
            for i in range(0, size, step):
                value=unpack('=idiq', x[i: i+step])
                value=list(value)
                value[3]=value[3]/1000
                #self.log.info('接收遥测%s'%str(value))
                self.RT.update({value[0]:value})

        elif rt_rtype == 0x0101022F and count>0:
            for i in range(0, size, step):
                value=unpack('=i128siq', x[i: i+step])
                value=list(value)
                value[3]=value[3]/1000
                #self.log.info('接收遥文'%str(value))
                self.RT.update({value[0]:value})
#SDK实时数据封装
class RtData(object):
    """docstring for RtData"""
    def __init__(self, log=print):
        super(RtData, self).__init__()
        self.log=log
        #检测log模块加载
        self.init_log()
        #读取SDK配置文件
        self.sdkConfigPath="./gcl_sdk/config/apps.config.ini"
        self.sdkConfig=ReadConfig.Config(self.sdkConfigPath).read()
        #print(int(self.sdkConfig['GeneralAccess']['PsmSentSourceId'],16))
        #SDK实例
        self.sdk = GCL_SDK(self.log)
        #回调实例
        self.sdk_cb = SDK_CB(self,self.log)
        #注册回调
        self.sdk_cb.set_callbacks()
        #初始化Sdk
        self.init_sdk()
    #初始化Sdk
    def init_sdk(self):
        pStr = c_char_p()
        sTemp = os.path.abspath('.') + "\\"
        pStr.value = sTemp.encode('gbk')
        a=self.sdk.init(1, byref(pStr))
    #初始化log
    def init_log(self):
        if not self.log:
            config={
                    'level':10,
                    #是否存储日志
                    'saveLog':'Y',
                    #存储日志路径
                    'logPath':'./log',
                    #日志文件切割周期 D,H,M,S,天，时，分，秒
                    'time':'H:1',
                    #存储日志个数
                    'saveNumber':168
                    }
            self.log=Logger(config).write
    #查询mid
    def get_measure(self,mid):

        return self.sdk_cb.RT.get(mid,None)
    #定单个值
    def set_measure(self,mid,value,q=1,t=int(time.time()*1000)):
        #遥信
        if mid and hex(int(mid))[2]=='1':
            #self.log.info("发送遥信：%s，值：%s，质量：%s，时间：%s"%(mid,value,q,t))
            e=GCL_YX_T()
            e.address  = int(mid)
            e.value    = int(value)
            e.quality  = q
            e.datetime =t
            rec=-1
            for i in range(4):
                rec=self.sdk.send_yx(e)
                if rec!=-1:
                    #self.log.info("发送成功")
                    break
                else:
                    time.sleep(0.1)
            if rec==-1:
                self.log.warning("发送5次没有发送成功")
                return False
            return rec
        #遥测
        elif mid and hex(int(mid))[2]=='2':
            #self.log.info("发送遥测：%s，值：%s，质量：%s，时间：%s"%(mid,value,q,t))
            e=GCL_YC_T()
            e.address  = int(mid)
            e.value    = float(value)
            e.quality  = q
            e.datetime =t
            rec=-1
            for i in range(4):
                rec=self.sdk.send_yc(e)
                if rec!=-1:
                    #self.log.info("发送成功")
                    break
            if rec==-1:
                self.log.warning("发送5次没有发送成功")
                return False
            return rec
        #遥文
        elif mid and hex(int(mid))[2]=='3':
            #self.log.info("发送遥文：%s，值：%s，质量：%s，时间：%s"%(mid,value,q,t))
            e=GCL_YW_T()
            e.address  = int(mid)
            e.value    = str(value).encode('utf-8') if isinstance(value,str) or isinstance(value,int) or isinstance(value,float) else value
            e.quality  = q
            e.datetime =t
            rec=-1
            for i in range(4):
                rec=self.sdk.send_yw(e)
                if rec!=-1:
                    #self.log.info("发送成功")
                    break
            if rec==-1:
                self.log.warning("发送5次没有发送成功")
                return False
            return rec
    #写多个值
    def set_measure_list(self,mid_value,q=1,t=int(time.time()*1000)):
        if mid_value and len(mid_value)>=1:
            yx=[]
            yc=[]
            yw=[]
            #组合数据
            for v in mid_value:
                try:
                    mid=v[0]
                    value=v[1]
                    #遥信
                    if mid and hex(int(mid))[2]=='1':
                        e=GCL_YX_T()
                        e.address  = int(mid)
                        e.value    = int(value)
                        e.quality  = q
                        e.datetime =t
                        yx.append(e)
                    #遥测
                    elif mid and hex(int(mid))[2]=='2':
                        e=GCL_YC_T()
                        e.address  = int(mid)
                        e.value    = float(value)
                        e.quality  = q
                        e.datetime =t
                        yc.append(e)
                    #遥文
                    elif mid and hex(int(mid))[2]=='3':
                        e=GCL_YW_T()
                        e.address  = int(mid)
                        e.value    = value
                        e.quality  = q
                        e.datetime =t
                        yw.append(e)
                except Exception as e:
                    self.log.warning("发送数据组格式错误，正确： [(mid1,value1)(mid2,value2)... ]")
            if len(yx)>=1:
                #self.log.info("发送%s个遥信"%(len(mid_value)))
                rec=-1
                for i in range(4):
                    rec=self.sdk.send_yx_array(yx)
                    if rec!=-1:
                        #self.log.info("发送成功")
                        break
                if rec==-1:
                    self.log.warning("发送5次没有发送成功")
                    return False
                return rec
            elif len(yc)>=1:
                #self.log.info("发送%s个遥测")
                rec=-1
                for i in range(4):
                    rec=self.sdk.send_yc_array(yx)
                    if rec!=-1:
                        #self.log.info("发送成功")
                        break
                if rec==-1:
                    self.log.warning("发送5次没有发送成功")
                    return False
                return rec
            elif len(yw)>=1:
                #self.log.info("发送%s个遥文")
                rec=-1
                for i in range(4):
                    rec=self.sdk.send_yw_array(yx)
                    if rec!=-1:
                        #self.log.info("发送成功")
                        break
                if rec==-1:
                    self.log.warning("发送5次没有发送成功")
                    return False
                return rec
    #读取消息
    def get_message(self):
        if self.sdk_cb.MSG.qsize()>=1:
            return self.sdk_cb.MSG.get()
        else:
            self.log.warning("没有接收到消息命令")
    def set_message(self,cmd,mid,value,attach=None):
        # e=GCL_PSM_ATTACH()
        # e.reason=0
        # e.containerId=0
        # e.sourceId=int(self.sdkConfig['GeneralAccess']['PsmSentSourceId'],16)
        # e.targetId=687931785
        # e.tag=0
        pram='measure=%s;value=%s;'%(mid,value)
        rec=self.sdk.send_msg(cmd,pram)
        print(rec)
if __name__ == '__main__':
    app=RtData()

    #print(app.init())
    #app.set_measure('16777216',8)
    while 1:
        app.set_measure('16777216',6)
        app.set_measure_list([(16777216,88),(16777217,99),(16777218,77)])
        #app.set_message('send.yk.1',16777216,8)
        time.sleep(5)


